package animator.phantom.exec;

/*
    Copyright Janne Liljeblad

    This file is part of Phantom2D.

    Phantom2D is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Phantom2D is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Phantom2D.  If not, see <http://www.gnu.org/licenses/>.
*/

import java.util.*;
import java.io.*;

//--- Runs a native command and stores output, errors and exitVal. If in runner, returns to runner.
public class NativeCommandExec
{
	protected Process p;
	protected String command;
	protected String workDir = null;
	protected File workDirFile = null;

	protected StreamBufferReader error;
	protected StreamBufferReader output;

	protected Timer cleanUp;
	protected int waitInSec;

	protected  NativeCommandRunner runner = null;

	protected NativeCommandExec selfReference;
	
	protected int exitVal = -1;

	public static final String ERROR_OUTPUT = "##¤¤%%&&!!??";//--- Just something unpropable.

	public NativeCommandExec( String command )
	{
		this.command = command;
		selfReference = this;//for inner timer task
	}

	public NativeCommandExec( String command, File execDir )
	{
		this.command = command;
		this.workDirFile = execDir;
		selfReference = this;//for inner timer task
	}

	public NativeCommandExec( String command, int waitInSec )
	{
		this.command = command;
		this.waitInSec = waitInSec;
		selfReference = this;//for inner timer task
		cleanUp = new Timer();
	}

	public NativeCommandExec( String command, String execDir, int waitInSec )
	{
		this.command = command;
		this.waitInSec = waitInSec;
		this.workDir = execDir;
		selfReference = this;//for inner timer task
		cleanUp = new Timer();
	}

	public void setRunner( NativeCommandRunner r ){ runner = r; }

	public void runCommand()
	{
		if( cleanUp != null ) cleanUp.schedule( new CleanUpTask(), waitInSec * 1000 );
		try
		{
			//--- Get runtime and start process with command.
			Runtime rt = Runtime.getRuntime();
			
			//--- Runu command in current dir
			if( workDir == null &&  workDirFile == null )
				p = rt.exec( command );
			else if( workDirFile == null ) // run command in specified directory
			{
				File wd = new File( workDir );
				p = rt.exec( command, null, wd );
				System.out.println( "wd abs:" + wd.getAbsolutePath() );
			}
			else // run command in specified directory
			{
				p = rt.exec( command, null, workDirFile );
				System.out.println( "wdfile abs:" + workDirFile.getAbsolutePath() );
			}
			//--- Get streams
			error = new StreamBufferReader( p.getErrorStream() );
			output = new StreamBufferReader( p.getInputStream() );
			
			//--- Start reader.
			error.start();
			output.start();

			//--- Blocks to wait and get exit val
			exitVal = p.waitFor();

			System.out.println("NativeCommandExec COMMAND DONE, command:" + command + ", exit value:" + exitVal);

			if( exitVal != 0 )
				System.out.println("ERROR_STREAM_OUT:" + getErrorStream() );

		} 
		catch ( Throwable t )
		{
			System.out.println("NativeCommandExec ERROR, command:" + command + ", exit value:" + exitVal);
			t.printStackTrace();
			if( cleanUp != null ) 
				cleanUp.cancel();
			System.out.println("command:" + command + " stack trace ends." );
			System.out.println("ERROR_STREAM_OUT:" + getErrorStream() );
			if( runner != null ) 
				runner.complete( this, true );
			
		}

		if( cleanUp != null ) 
			cleanUp.cancel();
		if( p != null )
			p.destroy();
		if( runner != null ) 
			runner.complete( this, true );
	}

	//--- Exit value from process
	public int getExitVal(){ return exitVal; }

	//--- Get contents of output stream.
	public String getOutputStream()
	{ 
		if( output == null ) return ERROR_OUTPUT;
		else
			return output.getBufferedString();
	}

	//--- Get contents of error stream.
	public String getErrorStream()
	{ 
		if( error == null ) return ERROR_OUTPUT;
		else
			return error.getBufferedString();
	}

	public void stop( boolean stopRunner )
	{
		if( cleanUp != null ) cleanUp.cancel();
		if( p != null )	p.destroy();
		if( runner != null && !stopRunner ) runner.complete( this, true );
	}

	//--- Kill command process if not completed in specified time.
	class CleanUpTask extends TimerTask
	{
		public void run()
		{
			System.out.println( "cleanuptask" );
			if( p != null ) p.destroy();
			if( runner != null ) runner.complete( selfReference, false );
		}
	}

}//end class